package com.whut.utils;

import com.alibaba.fastjson.JSON;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.Signature;
import org.aspectj.lang.annotation.*;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import javax.jms.Session;
import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpSession;
import java.lang.reflect.Method;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Date;
import java.util.stream.Collectors;


@Component
@Aspect
@Slf4j
public class LogAspect {
    private static final SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
    //切入点描述 这个是controller包的切入点
    @Pointcut("execution(public * com.whut.controller..*.*(..))&& !execution(public * com.whut.controller.MotorController.*(..))")
    //签名，可以理解成这个切入点的一个名称
    public void webLog() {
    }
    //环绕通知，执行webLog方法
    @Around("webLog()")
    public Object doBefore(ProceedingJoinPoint joinPoint) throws Throwable {
        ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
        HttpServletRequest request = attributes.getRequest();
        Cookie[] cookies = request.getCookies();
        String username = "";
        String tel = "";
        Cookie cookie = null;
        Cookie cookie1 = null;
        //拿用户名
        if(cookies != null){
            for (int j = 0; j < cookies.length; j++) {
                cookie = cookies[j];
                if (cookie.getName().equals("username")) {
                    username = cookie.getValue();
                }
            }
        }
        StringBuilder requestLog = new StringBuilder();
        Signature signature = joinPoint.getSignature();
        requestLog.append(username).append("\t").append(((MethodSignature) signature).getMethod()).append("\t")
                .append("请求信息：").append("URL = {").append(request.getRequestURI()).append("},\t")
                .append("请求方式 = {").append(request.getMethod()).append("},\t")
                .append("请求IP = {").append(request.getRemoteAddr()).append("},\t")
                .append("类方法 = {").append(signature.getDeclaringTypeName()).append(".")
                .append(signature.getName()).append("},\t");
        log.info(requestLog.toString());
        Date startDate = new Date();
        //返回目标方法所有的参数
        Object[] args = joinPoint.getArgs();
        //方法完整路径
        log.info("signature.toString()" + signature.toString());
        //方法开始调用的时间
        log.info("{} 调用时间：{}", signature, sdf.format(startDate));
        //计算方法的执行时间
        long start = System.currentTimeMillis();
            //用改变后的参数执行目标方法
        Object object = joinPoint.proceed();
            //目标执行完成并记录结束时间
        long end = System.currentTimeMillis();
        String time = this.formatExecuteTime(end - start);
        log.info("{} 执行时间：{}", signature.toString(), time);
        //方法参数
        (new Thread(() -> {
            log.info("{} 方法入参{}", signature.toString(),new ArrayList<>(Arrays.asList(args)).stream().map(a -> a.toString()).collect(Collectors.joining(",")));
        })).start();
        return object;
    }

    /**通过毫秒计算出时分秒并输出xxmxxsxxms的格式字符
     * @param executeTime
     * @return
     */
    private String formatExecuteTime(long executeTime) {
        long min = executeTime % 3600000L / 60000L;
        long sec = executeTime % 60000L / 1000L;
        long msec = executeTime % 10000L;
        StringBuilder sb = new StringBuilder();
        if(min > 0L) {
            sb.append(min).append("m ");
        }
        if(sec > 0L) {
            sb.append(sec).append("s ");
        }
        sb.append(msec).append("ms");
        return sb.toString();
    }
}

